import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subject } from 'rxjs';

import { CommonService } from '../services/common.service';
import { HttpRequestService } from '../services/http-request.service';
import { PendingHttpRequestService } from '../services/pending-http-request.service';
import { ServiceLocator } from '../shared/service.locator';

/**
 * Base class for component and directive. Completes some common tasks.
 * 
 * Angular now deprecated undecorated base classes that use Angular features.
 * That's why we have to put @Component here even we don't need it.
 * DO NOT DIRECTLY USE IT EXCEPT EXTENDING.
 */
@Component({
    selector: 'op-app-base-directive',
    template: ''
})
export abstract class BaseDirective implements OnInit, OnDestroy {
    hasPendingRequest: boolean = false;

    // When should I unsubscribe from `Subscription`
    // The solution we should all use going forward is to add a private ngUnsubscribe: Subject<void> = new Subject<void>(); 
    // field to all components that have .subscribe() calls to Observables within their class code.

    // We then call this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); in our ngOnDestroy() methods.

    // The secret sauce (as noted already by @metamaker) is to call .takeUntil(this.ngUnsubscribe) before each of our .subscribe() 
    // calls which will guarantee all subscriptions will be cleaned up when the component is destroyed.
    protected ngUnsubscribe: Subject<void> = new Subject<void>();

    protected commonService: CommonService;
    protected httpRequestService: HttpRequestService;
    private pendingHttpRequestService;

    constructor() {
        this.commonService = ServiceLocator.injector.get(CommonService);
        this.httpRequestService = ServiceLocator.injector.get(HttpRequestService);
        this.pendingHttpRequestService = ServiceLocator.injector.get(PendingHttpRequestService);
    }

    ngOnInit(): void {
        this.initializeProperties();
        this.viewScrollToTop();
    }

    ngOnDestroy(): void {
        this.unsubscribe();
    }

    /** 
     * Initializes the class properties if necessary.
    */
    protected initializeProperties(): void {
        // window.setTimeout solves Expression has changed after it was checked error.
        // Details check on https://blog.angular-university.io/angular-debugging/
        this.pendingHttpRequestService.currentPendingRequestCount$.subscribe((result: any) => {
            window.setTimeout(() => this.hasPendingRequest = result > 0, 0);
        });
    }

    /**
     * Scrolls current view to the top.
     */
    protected viewScrollToTop(): void {
        window.scrollTo(0, 0);
    }

    /**
     * Unsubscribes any observable.
     */
    protected unsubscribe(): void {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
    }
}